# -*- coding: utf-8 -*-
# standard
import os
import sys
import base64 
import json
from uuid import uuid4
from hashlib import md5
from datetime import datetime
from datetime import timedelta
from typing import List, Dict

# third
import requests
from Crypto.Cipher import AES        # pip install pycryptodome
from Crypto.Cipher import PKCS1_v1_5
from Crypto.PublicKey import RSA  
from Crypto.Util.Padding import pad, unpad  


# local
_P_PATH =  os.path.dirname(os.path.dirname(os.path.realpath(__file__)))
if _P_PATH not in sys.path:
    sys.path.append(_P_PATH)
from toolbox.common_tools import logger
from db import *


"""
@Title:   
@File: ruiju_func.py
@Author: walle 2024年11日06日 14时44分32秒
@Version: 1.0.0
@Desc: 
"""



####################上海睿据电力传感器############################


RUIJU_INFO = {}  # 睿据的信息比如加密的key，一般不会变动
RUIJU_CLIENT_ID = "yhjkxxjk"
RUIJU_CLIENT_SECRET = "E0E15D76EA9A09CD44F96DDE6179203D"


def ruiju_fetch_get_public_key_from_server() -> Resp:
    """
    获取公钥
    """
    resp = Resp()
    url = 'https://rejuvee.net/PowerManager/AppClientAction_getPublicKeyContent.do'
    response = None
    try:
        response = requests.get(url=url)
    except Exception as e:
        logger.error(e)
        resp.message = f"请求睿据公钥失败:{e}"
    finally:
        if resp:
            if response.status_code != 200:
                resp.message = f"服务端返回了错误的状态码:{response.status_code}"
            else:
                data = response.json()
                if data['code'] == 1:
                    encrypted_public_key = data['data']['publicKey']
                    resp.data = encrypted_public_key
        else:
            pass
        return resp
    
    
def ruiju_generate_aes_key(encrypted_public_key: str, key: str | bytes) -> Resp:
    """
    生成aeskey
    """
    publicKey_pem = base64.b64decode(encrypted_public_key)  
    public_key = RSA.import_key(publicKey_pem)  
    cipher_rsa = PKCS1_v1_5.new(public_key) 
    text =  cipher_rsa.encrypt(key.encode("utf-8") if isinstance(key, str) else key)
    cipher_text = base64.b64encode(text).decode("utf-8")
    return cipher_text


def ruiju_get_headers():
    """
    睿据填充请求头
    """
    headers = {
        'Content-Type': 'application/json'
    }
    access_token = RUIJU_INFO['access_token']
    expiry_time = datetime.strptime(RUIJU_INFO['expiry_time'], "%Y-%m-%d %H:%M:%S")
    if (expiry_time - datetime.now()).total_seconds() < 5:
        # 如果token过期，重新获取token
        access_token = ruiju_fetch_access_token()
    headers['token'] = access_token
    return headers


def encrypt_payload(payload: dict) -> str:
    """
    用aeskey 加密 数据负载
    """
    block_size = AES.block_size
    text = json.dumps(payload)
    key = RUIJU_INFO['aes_key']
    cipher = AES.new(key=key.encode(), mode=AES.MODE_ECB)
    padded_data = pad(text.encode('utf-8'), block_size, "pkcs7")
    encrypted_data = cipher.encrypt(padded_data) 
    return base64.b64encode(encrypted_data).decode("utf-8")


def decrypt_str(encrypted_str: str) -> str:
    """
    用aeskey 解密 数据负载
    """
    block_size = AES.block_size
    key = RUIJU_INFO['aes_key']
    cipher = AES.new(key=key.encode(), mode=AES.MODE_ECB)
    encrypted_data = base64.b64decode(encrypted_str)
    decrypted_data = cipher.decrypt(encrypted_data)
    unpadded_data = unpad(decrypted_data, block_size, "pkcs7")
    return unpadded_data.decode('utf-8')


def ruiju_send_request(method: str, url: str, **kwargs) -> Resp:
    """
    睿据的发送请求
    """
    if method.lower() == "get":
        handler = requests.get
    else:
        handler = requests.post
    resp = Resp()
    response = None
    if "headers" not in kwargs:
        headers = ruiju_get_headers()
        kwargs['headers'] = headers
    try:
        if json_dict := kwargs.get("json"):
            kwargs['json'] = encrypt_payload(json_dict)
        response = handler(url=url, **kwargs)
    except Exception as e:
        logger.error(e)
        resp.message = f"请求睿据接口失败:{e}"
    finally:
        if resp:
            if response.status_code != 200:
                resp.message = f"服务端返回了错误的状态码:{response.status_code}"
            else:
                bad_json = None
                try:
                    bad_json = response.json()
                except Exception as e:
                    logger.error(e)
                    resp.message = f"解析睿据返回的结果失败:{e}"
                if bad_json:
                    resp.message = f"服务端返回了错误的数据:{bad_json}"
                else:  
                    data = response.text
                    data = decrypt_str(data)
                    data = json.loads(json.loads(data))
                    if data['code'] != 1:
                        resp.message = f"code:{data['code']}, message: {data['message']}"
                    else:
                        resp.data = data['data']
        else:  # 无需处理
            ...
    return resp


def ruiju_upload_ase_key() -> str:
    """
    上传aeskey 返回session id
    """
    url = 'https://rejuvee.net/PowerManager/AppClientAction_commitAesKey.do'
    headers = {'iToken': RUIJU_INFO['pk']}
    response = requests.post(url=url, headers=headers)
    return response.cookies.get('JSESSIONID')


def ruiju_login() -> Resp:
    """
    睿据登录
    """
    j_session = ruiju_upload_ase_key()
    json_dict = {
        "account": "yhxlj",
        "password": md5("yh-123456".encode("utf-8")).hexdigest(),
        "clientID": RUIJU_CLIENT_ID,
        "clientSecret": RUIJU_CLIENT_SECRET,
    }
    headers = {
            # 第一次登录需要带上 提交秘钥时的token来认证身份
            'cookie': 'JSESSIONID=%s' % j_session,
            'content-type': 'application/json'
        }
    url = "https://rejuvee.net/PowerManager/AppClientAction_getToken.do"
    resp = ruiju_send_request(method='post', url=url, headers=headers, json=json_dict)
    if resp:
        data = resp.data
        data['pk'] = RUIJU_INFO['pk']
        data['aes_key'] = RUIJU_INFO['aes_key']
        expiry_time = datetime.now() + timedelta(seconds=data['expires_in'])
        expiry_time = expiry_time.strftime('%Y-%m-%d %H:%M:%S')
        data['expiry_time'] = expiry_time
        with open(file=os.path.join(R_P_PATH, "configure", "ruiju_key.json"), mode="w", encoding="utf-8") as f:
            json.dump(data, f)
        RUIJU_INFO.update(data)
    return resp


def ruiju_fetch_access_token() -> str:
    """
    获取access token
    """
    refresh_token = RUIJU_INFO['refresh_token']
    url = "https://rejuvee.net/PowerManager/AppClientAction_refreshToken.do"
    json_dict = {
        "clientID": RUIJU_CLIENT_ID,
        "clientSecret": RUIJU_CLIENT_SECRET,
        'refresh_token': refresh_token
    }
    resp = ruiju_send_request(method='post', url=url, json=json_dict)
    if resp:
        ...
    else:
        raise ValueError(resp.message)
    

def ruiju_get_current_user_info() -> Resp:
    """
    获取当前用户信息
    """
    url = "https://rejuvee.net/PowerManager/AppClientAction_getUserMsg.do"
    resp = ruiju_send_request(method='post', url=url)
    return resp

    
def ruiju_init_key():
    """
    睿据初始化 aes_key 
    """
    file_path = os.path.join(R_P_PATH, "configure", "ruiju_key.json")
    with open(file=file_path, mode="r", encoding="utf-8") as f:
        data = json.load(fp=f)
        refresh_token = data.get('refresh_token')
    if not refresh_token:
        resp = ruiju_fetch_get_public_key_from_server()
        if not resp:
            logger.error(f"初始化睿据的公钥失败: {resp.message}")
        else:
            aes_key = uuid4().hex[-16:]
            pk = ruiju_generate_aes_key(resp.data, aes_key)
            RUIJU_INFO['aes_key'] = aes_key
            RUIJU_INFO['pk'] = pk
            ruiju_login()
    else:
        RUIJU_INFO.update(data)
    

def ruiju_get_collectors() -> Resp:
    """
    获取睿据的电箱列表
    """
    url = "https://rejuvee.net/PowerManager/AppClientAction_getCollectorList.do"
    resp = ruiju_send_request(method='post', url=url)
    return resp


def test():
    # 睿据的测试函数
    ...



if __name__ == '__main__':
    pass